<?php
require_once (dirname(__FILE__) . "/../../config.php");
require_once (dirname(__FILE__) . "/../init.php");
require_once (dirname(__FILE__) . "/../common/crypt/Crypt.php");
?>
<?php

/*
 * Host DB
 * Created: 200904 (TT Tsai)
 *
 * The base class for ServerList and ProxyList
 */
class WFHostDao
{
    // main database object
    private $hostdb;
    private $hdbtable;
    // encryption object
    private $enc_obj;
    // error handling
    private $errMessage = "";
    private $errCode = 0;
    // userid
    // - build-in permission control (build-in support)
    // - if userid was not specified, the function would be ignored.
    private $userid = 0;
    /**
     * @var WF
     */
    private $objFramework;
    protected function permission_check($rid){
        if($rid == 1){
            $ret = true;
        }else{
            $ridOrGuid = $rid;
            $colNameRidOrGuid = 'id';
            $ret = $this->permission_checkByCondition($ridOrGuid, $colNameRidOrGuid);
        }
        return $ret;
    } 
    protected function permission_checkByGuid($guid){
        if(!$guid){
            $ret = false;
        }else{
            return true; //always return true @todo
            $ridOrGuid = $guid;
            $colNameRidOrGuid = 'guid';
            $ret = $this->permission_checkByCondition($ridOrGuid, $colNameRidOrGuid);
        }
        return $ret;
    }
    // get owner id of the record
    protected function permission_checkByCondition($ridOrGuid, $colNameRidOrGuid){
        if($this->userid != 0){
            $objParameter = WF::getParameter();
            $objParameter->appendSelect("owner");
            $objParameter->appendFrom($this->hdbtable);
            $objParameter->andWhereEqual($colNameRidOrGuid, $ridOrGuid);
            $query_result = WF::getDataObject()->querySelectAllByParameter($objParameter);
            if(false === $query_result){
                return FALSE;
            }
            // get owner id
            $record_owner_id = $query_result[0]["owner"];
            // check
            if($this->userid != $record_owner_id){
                return FALSE;
            }
        }
        return TRUE;
    }
    // private methods
    private function runSQL($sqlstring, $sqlvalues, $estring, $ecode){
        $query_result = $this->hostdb->query($sqlstring, $sqlvalues);
        // check error
        if($this->hostdb->isFailed()){
            $this->errMessage = $estring . ": " . $this->hostdb->getErrMessage();
            $this->errCode = $ecode;
            return FALSE;
        }
        return $query_result;
    }
    private function setError($strErrMessage, $intErrCode){
        $this->errMessage = $strErrMessage . ": " . WF::getDataObject()->getErrMessage();
        $this->errCode = $intErrCode;
        return FALSE;
    }
    // Constructor
    public function __construct($tbl, $dbconfig, $uid){
        $this->hdbtable = $tbl;
        $this->userid = $uid;
        //$this->hostdb = new WFDatabaseObject($dbconfig);
        $this->objFramework = WF::getInstance();
        $this->hostdb = $this->objFramework->getDataObject();
        // check error
        //william su - DataObject is singleton, so if check error will cause error
        /*if( $this->hostdb->isFailed() ) {
            $this->errMessage =  "Database initialization failed: ".$this->hostdb->getErrMessage();
            $this->errCode = 1;
        }*/
        // init encryption object
        $this->enc_obj = new WFCrypt();
        if($this->enc_obj->isFailed()){
            $this->errMessage = "Encryption module failed(init): " . $this->enc_obj->getErrMessage();
            $this->errCode = 1;
        }
        return;
    }
    // Destructor
    public function __destruct(){
        unset($this->hostdb);
        unset($this->enc_obj);
    }
    // set user id
    public function setuid($id){
        $this->userid = $id;
    }
    // add
    public function add($sname, $sinfo){
        $objParameter = WF::getParameter();
        $objParameter->appendFrom($this->hdbtable);
        $assocData = array();
        $assocData['owner'] = $this->userid;
        $assocData['deleted'] = 0;
        $assocData['lastcheck'] = 0;
        $assocData['name'] = $sname;
        $assocData['hostinfo'] = $sinfo;
        $objParameter->setAssocData($assocData);
        $result = WF::getDataObject()->queryInsertByParameter($objParameter);
        if(false === $result){
            $strErrMessage = "Adding server failed";
            $intErrCode = 1;
            $this->setError($strErrMessage, $intErrCode);
        }
        return $result;
    }
    // del
    public function del($rid){
        // permission check
        if($this->permission_check($rid) == FALSE){
            $this->errMessage = "Permission denied";
            $this->errCode = 1;
            return;
        }
        $objParameter = WF::getParameter();
        $objParameter->appendFrom($this->hdbtable);
        $objParameter->andWhereEqual('id', $rid);
        $result = WF::getDataObject()->queryDeleteByParameter($objParameter);
        if(false === $result){
            $strErrMessage = "Deleting server failed";
            $intErrCode = 2;
            $this->setError($strErrMessage, $intErrCode);
        }
        return $result;
    }
    // update
    public function update($rid, $sname, $sinfo){
        // permission check
        if($this->permission_check($rid) == FALSE){
            $this->errMessage = "Permission denied";
            $this->errCode = 1;
            return;
        }
        $objParameter = WF::getParameter();
        $objParameter->appendFrom($this->hdbtable);
        $assocData = array();
        $assocData['owner'] = $this->userid;
        $assocData['name'] = $sname;
        $assocData['hostinfo'] = $sinfo;
        $objParameter->setAssocData($assocData);
        $objParameter->andWhereEqual('id', $rid);
        $result = WF::getDataObject()->queryUpdateByParameter($objParameter);
        if(false === $result){
            $strErrMessage = "Updating server failed";
            $intErrCode = 3;
            $this->setError($strErrMessage, $intErrCode);
        }
        return $result;
    }
    // update lastcheck
    public function update_lastcheck($rid, $timestamp){
        $objParameter = WF::getParameter();
        $objParameter->appendFrom($this->hdbtable);
        $assocData = array();
        $assocData['lastcheck'] = $timestamp;
        $objParameter->setAssocData($assocData);
        $objParameter->andWhereEqual('id', $rid);
        $result = WF::getDataObject()->queryUpdateByParameter($objParameter);
        if(false === $result){
            $strErrMessage = "Updating lastcheck failed";
            $intErrCode = 4;
            $this->setError($strErrMessage, $intErrCode);
        }
        return $result;
    }
    // getall_nofilter
    public function getall_nofilter(){
        $result_array = array();
        if($this->userid != 0){
            // get shared list
            $objParameter = WF::getParameter();
            $objParameter->appendFrom($this->hdbtable);
            $objParameter->andWhereEqual('owner', 0);
            $result_array = WF::getDataObject()->querySelectAllByParameter($objParameter);
            if(false === $result_array){
                $strErrMessage = "Getting server list failed";
                $intErrCode = 5;
                $this->setError($strErrMessage, $intErrCode);
                return FALSE;
            }
            // get owner's list
            $objParameter = WF::getParameter();
            $objParameter->appendFrom($this->hdbtable);
            $objParameter->andWhereEqual('owner', $this->userid);
            $result_array2 = WF::getDataObject()->querySelectAllByParameter($objParameter);
            if(false === $result_array2){
                $strErrMessage = "Getting server list failed";
                $intErrCode = 5;
                $this->setError($strErrMessage, $intErrCode);
                return FALSE;
            }
            $result_array = array_merge($result_array, $result_array2);
        }else{
            $objParameter = WF::getParameter();
            $objParameter->appendFrom($this->hdbtable);
            $result_array = WF::getDataObject()->querySelectAllByParameter($objParameter);
            if(false === $result_array){
                $strErrMessage = "Getting server list failed";
                $intErrCode = 5;
                $this->setError($strErrMessage, $intErrCode);
                return FALSE;
            }
        }
        // json decode hostinfo
        foreach($result_array as $key => $rec){
            $hostobj = json_decode($rec["hostinfo"], true);
            if($hostobj != null){
                $result_array[$key]["hostinfo"] = $hostobj;
            }
        }
        // decrypt password in hostinfo
        foreach($result_array as $key => $rec){
            if(isset($rec["hostinfo"]["password"])){
                $result_array[$key]["hostinfo"]["password"] = $this->decrypt($rec["hostinfo"]["password"]);
            }
        }
        return $result_array;
    }
    // getall
    public function getall(){
        $result_array = $this->getall_nofilter();
        if($this->isFailed()){
            return FALSE;
        }
        // filter deleted items
        $f_array = array();
        foreach($result_array as $key => $rec){
            if($rec["deleted"] == "0"){
                $f_array[] = $result_array[$key];
            }
        }
        return $f_array;
    }
    // getserverlisttype
    public function getserverlisttype(){
        $result_array = $this->getserverlisttype_nofilter();
        if($this->isFailed()){
            return FALSE;
        }
        return $result_array;
    }
    public function getinfo($rid){
        $ridOrGuid = $rid;
        $searchByColumnName = 'id';
        return $this->getinfoByCondition($ridOrGuid, $searchByColumnName);
    }
    public function getinfoByGuid($guid){
        $ridOrGuid = $guid;
        $searchByColumnName = 'guid';
        return $this->getinfoByCondition($ridOrGuid, $searchByColumnName);
    }
    protected function getinfoByCondition($ridOrGuid, $searchByColumnName){
        if($searchByColumnName == 'id'){
            $strFuncNameGetOriginalInfo = 'getOriginalInfo';
        }else{
            $strFuncNameGetOriginalInfo = 'getOriginalInfoBy'.$this->objFramework->getTypeFactory()->getString()->getUpperCamelCase($searchByColumnName);
        }
        $query_result = $this->$strFuncNameGetOriginalInfo($ridOrGuid);
        
        if($this->errCode != 0){
            return FALSE;
        }
        if(isset($query_result[0])){
            $jsonobj = json_decode($query_result[0]["hostinfo"], true);
            if($jsonobj == null){
                return $query_result[0];
            }
            // decrypt password
            if(isset($jsonobj["password"]) && $jsonobj["password"] != ""){
                $jsonobj["password"] = $this->decrypt($jsonobj["password"]);
            }
            if(isset($jsonobj["customFields"]["password"]) && is_array($jsonobj["customFields"]["password"])){
                foreach($jsonobj["customFields"]["password"] as $key => $value){
                    $jsonobj["customFields"]["password"][$key] = $this->decrypt($value);
                }
            }
            return $jsonobj;
        }
        return json_decode("", true);
    }
    public function getOriginalInfo($rid){
        $ridOrGuid = $rid;
        $searchByColumnName = 'id';
        return $this->getOriginalInfoByCondition($ridOrGuid, $searchByColumnName);
    }
    public function getOriginalInfoByGuid($gid){
        $ridOrGuid = $gid;
        $searchByColumnName = 'guid';
        return $this->getOriginalInfoByCondition($ridOrGuid, $searchByColumnName);
    }
    protected function getOriginalInfoByCondition($ridOrGuid, $searchByColumnName){
        if($searchByColumnName == 'id'){
            $strFuncNamePermissionCheck = 'permission_check';
        }else{
            $strFuncNamePermissionCheck = 'permission_checkBy'.$this->objFramework->getTypeFactory()->getString()->getUpperCamelCase($searchByColumnName);
        }
        // permission check
        // if id=1 skip permission check
        // if id>1 exec permission check
        // if guid exec permission check
        if($this->$strFuncNamePermissionCheck($ridOrGuid) == FALSE){
            $this->errMessage = "Permission denied";
            $this->errCode = 1;
            return FALSE;
        }
        $objParameter = WF::getParameter();
        $objParameter->appendFrom($this->hdbtable);
        $objParameter->andWhereEqual($searchByColumnName, $ridOrGuid);
        $query_result = WF::getDataObject()->querySelectAllByParameter($objParameter);
        if(false === $query_result){
            $strErrMessage = "Getting server info failed";
            $intErrCode = 5;
            $this->setError($strErrMessage, $intErrCode);
            return FALSE;
        }
        return $query_result;
    }
    public function getlastid(){
        return $this->hostdb->lastInsertId();
    }
    /*
     * Encryption
     */
    public function encrypt($plain_str){
        $enc_str = $this->enc_obj->encrypt($plain_str);
        if($this->enc_obj->isFailed()){
            $this->errMessage = "encryption module failed(encrypt): " . $this->enc_obj->getErrMessage();
            return;
        }
        return $enc_str;
    }
    public function decrypt($enc_str){
        $plain_str = $this->enc_obj->decrypt($enc_str);
        if($this->enc_obj->isFailed()){
            $this->errMessage = "encryption module failed(decrypt): " . $this->enc_obj->getErrMessage();
            return;
        }
        return $plain_str;
    }
    /*
     * Error handling
     */
    public function isFailed(){
        if($this->errCode != 0 || $this->errMessage != ""){
            return TRUE;
        }
        return FALSE;
    }
    public function getErrMessage(){
        return $this->errMessage;
    }
    public function getErrCode(){
        return $this->errCode;
    }
}
?>
